#include <ptgui/ptgui.h>
#include <ptgui/pagectl.h>
#include <ptgui/widgets/scene.h>
#include <ptgui/pages/page.h>

typedef	struct ptgui_page_transfer_mode
{
	ptgui_page_stack_t *(*transfer_function)(ptgui_page_stack_t *, ptgui_page_control_t);
	rt_uint32_t	transfer_switch;
}	ptgui_page_transfer_mode_t;

/*	the current doing switch	*/
typedef	struct	ptgui_page_cursor_info
{
	ptgui_page_cell_t		*page_cell;
	ptgui_page_switch_view_t *switch_view;
	rt_uint8_t switch_state;
	rt_uint8_t switch_type;
}	ptgui_page_cursor_info_t;

enum	{
	PTGUI_PAGE_LAYER_LOWER_0,
	PTGUI_PAGE_LAYER_LOWER_1,
	PTGUI_PAGE_LAYER_LOWER_2,
	PTGUI_PAGE_LAYER_LOWER_3,
	PTGUI_PAGE_LAYER_LOWER_4,
	PTGUI_PAGE_LAYER_LOWER_5,
	PTGUI_PAGE_LAYER_LOWER_6,

	PTGUI_PAGE_LAYER_LOWER_MAX
};

enum	{
	PTGUI_PAGE_LAYER_UPPER_0,
	PTGUI_PAGE_LAYER_UPPER_1,
	PTGUI_PAGE_LAYER_UPPER_2,

	PTGUI_PAGE_LAYER_UPPER_MAX
};

#define	PTGUI_PAGE_NORMAL_STACK_MAX	10
#define	PTGUI_PAGE_FIX_STACK_MAX	(PTGUI_PAGE_LAYER_LOWER_MAX + PTGUI_PAGE_LAYER_UPPER_MAX)
#define	PTGUI_PAGE_STACK_MAX		(PTGUI_PAGE_NORMAL_STACK_MAX + PTGUI_PAGE_FIX_STACK_MAX)

static ptgui_page_stack_t pile_stack_array[PTGUI_PAGE_STACK_MAX + 1];
static ptgui_page_stack_t *pile_stack_normal_base;
static ptgui_page_stack_t *pile_stack_normal_top;
static ptgui_page_stack_t *pile_stack_lower_base;
static ptgui_page_stack_t *pile_stack_lower_top;
static ptgui_page_stack_t *pile_stack_upper_base;
static ptgui_page_stack_t *pile_stack_upper_top;
static rt_uint16_t piple_stack_count;

/*	Pushed switch info	*/
static	ptgui_page_cursor_info_t current_cursor_info;
static	ptgui_page_cursor_info_t moved_cursor_info;

rt_uint8_t key_event_break_flag;

static	struct	ptgui_page_control lastTransferCtrlBucket;		/*	transfer control bucket				*/

static	ptgui_page_stack_t			*lastRecentPile;				/*	the last doing function pile	*/
static	ptgui_page_stack_t			*lastProcessPile;				/*	the last doing function pile	*/
static	ptgui_page_switch_view_t	*lastSwitchView;	
static	ptgui_event_t				lastKeyEvent;
/*******************************************************************************
*	the bucket for transfer control 
*******************************************************************************/
ptgui_page_control_t ptgui_page_make_transfer_control_bucket(rt_uint32_t transfer_status,
															   const ptgui_page_cell_t *requese_page, rt_uint16_t	layer)
{
	/*	 Transfer control  Bucket  init 	*/
	ptgui_memset(&lastTransferCtrlBucket, 0, sizeof(lastTransferCtrlBucket));

	lastTransferCtrlBucket.transfer_status = transfer_status;										/*	 Transfer Type 		*/
	lastTransferCtrlBucket.transfer_layer = layer;
	lastTransferCtrlBucket.request_page_cell = requese_page;

	return (ptgui_page_control_t)&lastTransferCtrlBucket;
}

ptgui_page_control_t ptgui_page_transfer_call_normal(ptgui_page_cell_t *requese_page)
{
	return	ptgui_page_make_transfer_control_bucket((PAGE_RIDE) | (INHIBITION_ALL), requese_page,
													PTGUI_PAGE_LAYER_MAKE_NORMAL(0));
}

ptgui_page_control_t ptgui_page_transfer_call_inherit(ptgui_page_cell_t *requese_page)
{
	return	ptgui_page_make_transfer_control_bucket(INHERIT_ON | (PAGE_RIDE) | (INHIBITION_ALL), requese_page,
													PTGUI_PAGE_LAYER_MAKE_NORMAL(0));
}

ptgui_page_control_t ptgui_page_transfer_return_normal(void)
{
	return	ptgui_page_make_transfer_control_bucket(PAGE_RETURN | INSURANCE_ON | INHIBITION_NONE,
													PTGUI_PAGE_REF_PAGECELL(FP_PAGE_BOOT),
													PTGUI_PAGE_LAYER_MAKE_NORMAL(0));
}

ptgui_page_control_t ptgui_page_transfer_break(void)
{
	return (ptgui_page_control_t)ptgui_page_transfer_break;
}

void ptgui_page_key_event_break(void)
{
	key_event_break_flag = RT_TRUE;
}
/************************************************************************/
/*  																	*/
/************************************************************************/
static	ptgui_status_t ptgui_page_pile_transform(ptgui_page_stack_t *stack_pile, ptgui_page_entry_type_t request,
											   rt_int8_t factor)
{
	const ptgui_page_cell_t *page_cell;

	if (!stack_pile) {
		return PTGUI_STATUS_FAILED;
	}

	page_cell = stack_pile->page_cell;

	if (!page_cell) {
		return PTGUI_STATUS_FAILED;
	}

	if (0 <= factor) {
		lastRecentPile = stack_pile;
	}

	(*((page_cell)->entry_handler))(request);

	return PTGUI_STATUS_SUCCESS;
}

static	ptgui_status_t ptgui_page_stack_register(ptgui_page_stack_t *stack_pile, ptgui_page_control_t control)
{
	stack_pile->page_cell = control->request_page_cell;
	return PTGUI_STATUS_SUCCESS;
}

static	rt_uint8_t ptgui_page_is_register(const ptgui_page_cell_t *target)
{
	ptgui_page_stack_t *stack_pile;

	stack_pile = pile_stack_upper_top; 	
	while(stack_pile >= pile_stack_array) {
		if ((NULL != stack_pile) && (target == stack_pile->page_cell)) {
			return RT_TRUE;
		}

		stack_pile--;
	}

	return RT_FALSE;
}

static ptgui_page_stack_type_t ptgui_page_get_stack_type(ptgui_page_stack_t *stack_pile)
{
	if ((stack_pile >= pile_stack_lower_base) && (stack_pile < pile_stack_normal_base)) {
		return	RTGUI_PAGE_STACK_TYPE_LOWER;
	}
	else if ((stack_pile >= pile_stack_normal_base) && (stack_pile < pile_stack_upper_base)) {
		return	RTGUI_PAGE_STACK_TYPE_NORMAL;
	}
	else if ((stack_pile >= pile_stack_upper_base) && (stack_pile < pile_stack_array + PTGUI_PAGE_STACK_MAX)) {
		return	RTGUI_PAGE_STACK_TYPE_UPPER;
	}
	else {
		return	RTGUI_PAGE_STACK_TYPE_NONE;
	}
}

static rt_uint16_t ptgui_page_get_stack_size(ptgui_page_stack_type_t stack_type)
{
	switch(stack_type) {
	case RTGUI_PAGE_STACK_TYPE_LOWER:
		return pile_stack_lower_top - pile_stack_lower_base;
	case RTGUI_PAGE_STACK_TYPE_NORMAL:
		return pile_stack_normal_top - pile_stack_normal_base;
	case RTGUI_PAGE_STACK_TYPE_UPPER:
		return pile_stack_upper_top - pile_stack_upper_base;
	default:
		return 0;
	}
}

static	ptgui_status_t ptgui_page_hold_pile(ptgui_page_stack_t *stack_pile)
{
	ptgui_page_stack_type_t stack_type;

	stack_type = ptgui_page_get_stack_type(stack_pile);
	switch(stack_type) {
	case RTGUI_PAGE_STACK_TYPE_LOWER:
		ptgui_memmove(stack_pile + 1, stack_pile, (pile_stack_lower_top - stack_pile) * sizeof(*stack_pile));
		ptgui_memset(stack_pile, 0, sizeof(*stack_pile));
		pile_stack_lower_top++;
		break;
	case RTGUI_PAGE_STACK_TYPE_NORMAL:
		ptgui_memmove(stack_pile + 1, stack_pile, (pile_stack_normal_top - stack_pile) * sizeof(*stack_pile));
		ptgui_memset(stack_pile, 0, sizeof(*stack_pile));
		pile_stack_normal_top++;
		break;
	case RTGUI_PAGE_STACK_TYPE_UPPER:
		ptgui_memmove(stack_pile + 1, stack_pile, (pile_stack_upper_top - stack_pile) * sizeof(*stack_pile));
		ptgui_memset(stack_pile, 0, sizeof(*stack_pile));
		pile_stack_upper_top++;
		break;
	default:
		return PTGUI_STATUS_FAILED;
	}		

	return PTGUI_STATUS_SUCCESS;
}

/*	 Pile page_cell Delete 	*/
static	ptgui_page_stack_t *ptgui_page_delete_Pile(ptgui_page_stack_t *stack_pile)
{
	ptgui_page_stack_type_t stack_type;

	stack_type = ptgui_page_get_stack_type(stack_pile);
	switch(stack_type) {
	case RTGUI_PAGE_STACK_TYPE_LOWER:
		ptgui_memmove(stack_pile, stack_pile + 1, (pile_stack_lower_top - stack_pile) * sizeof(*stack_pile));
		ptgui_memset(pile_stack_lower_top, 0, sizeof(*pile_stack_lower_top));
		pile_stack_lower_top--;
		return stack_pile--;
	case RTGUI_PAGE_STACK_TYPE_NORMAL:
		ptgui_memmove(stack_pile, stack_pile + 1, (pile_stack_normal_top - stack_pile) * sizeof(*stack_pile));
		ptgui_memset(pile_stack_normal_top, 0, sizeof(*pile_stack_lower_top));
		pile_stack_lower_top--;
		return stack_pile--;
	case RTGUI_PAGE_STACK_TYPE_UPPER:
		ptgui_memmove(stack_pile, stack_pile + 1, pile_stack_upper_top - stack_pile - 1);
		ptgui_memset(pile_stack_upper_top, 0, (pile_stack_upper_top - stack_pile) * sizeof(*stack_pile));
		pile_stack_upper_top--;
		return stack_pile--;
	default:
		return stack_pile;
	}
}

ptgui_status_t ptgui_page_delete_stack_pile(rt_uint8_t	layer)
{
	ptgui_page_stack_t *stack_pile;
	ptgui_page_stack_t *lastPile;
		
	stack_pile = NULL;
	lastPile = lastRecentPile;

	if( layer & PTGUI_PAGE_LAYER_LOWER_MASK  ) {
		stack_pile = pile_stack_lower_base+(layer& 0x0F);
		//Can't delete the base layer
		if  (stack_pile==pile_stack_lower_base) {
			return PTGUI_STATUS_FAILED;
		}
	}
	else if( layer & PTGUI_PAGE_LAYER_UPPER_MASK  ) {
		stack_pile = pile_stack_upper_base+(layer& 0x0F);
	}
	else if(layer & PTGUI_PAGE_LAYER_NORMAL_MASK) {
		stack_pile = pile_stack_normal_base+(layer& 0x0F);
	}
	else {
	}

	if(NULL == stack_pile || NULL == stack_pile->page_cell){
		return PTGUI_STATUS_FAILED;
	}

	//Can't delete itself !!!
	if (lastRecentPile == stack_pile) {
		return PTGUI_STATUS_FAILED;
	}
	
	ptgui_page_pile_transform(stack_pile,PTGUI_PAGE_TERMINATE_ALL,0);
	
	ptgui_page_pile_transform(stack_pile,PTGUI_PAGE_TERMINATE_LST,0);

	return	PTGUI_STATUS_SUCCESS;
}

static	ptgui_page_stack_t * ptgui_page_change_pile(ptgui_page_stack_t *stack_pile, ptgui_page_control_t control)
{
	if (stack_pile == pile_stack_lower_base) {
		if ((stack_pile->page_cell) == (PTGUI_PAGE_REF_PAGECELL(FP_PAGE_BOOT))) {
			return	stack_pile;
		}
	}

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_TERMINATE_ALL, 0);

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_TERMINATE_LST, 0);

	ptgui_page_stack_register(stack_pile, control);

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_PREPARE_FST, 0);

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_PREPARE_ALL, 0);

	return stack_pile;
}

static	rt_uint8_t ptgui_page_is_top(ptgui_page_stack_t *stack_pile)
{
	return ((stack_pile + 1)->page_cell) ? RT_TRUE : RT_FALSE;
}

static	ptgui_page_stack_t * ptgui_page_ride_pile(ptgui_page_stack_t *stack_pile, ptgui_page_control_t control)
{
	ptgui_page_view_handle_t TopViewHBack = 0;

	ptgui_page_hold_pile(stack_pile + 1);

	ptgui_page_stack_register(stack_pile + 1, control);	

	ptgui_page_pile_transform(stack_pile + 1, PTGUI_PAGE_PREPARE_FST, 0);

	ptgui_page_pile_transform(stack_pile + 1, PTGUI_PAGE_PREPARE_ALL, 0);

	piple_stack_count++;
	return stack_pile;
}

static	ptgui_page_stack_t * ptgui_page_return_pile(ptgui_page_stack_t *stack_pile, ptgui_page_control_t control)
{
	if (stack_pile == pile_stack_lower_base) {
		if ((stack_pile->page_cell) == PTGUI_PAGE_REF_PAGECELL(FP_PAGE_BOOT)) {
			return	stack_pile;
		}
		else {
			return ptgui_page_change_pile(stack_pile, control);
		}
	}
	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_TERMINATE_ALL, 0);

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_TERMINATE_LST, 0);	

	stack_pile = ptgui_page_delete_Pile(stack_pile);	

	ptgui_page_pile_transform(stack_pile, PTGUI_PAGE_PREPARE_ALL, 0);

	piple_stack_count--;
	return stack_pile;
}

static	ptgui_page_stack_t * ptgui_page_rewind_pile(ptgui_page_stack_t *stack_pile, ptgui_page_control_t control)
{
	for (; stack_pile!= NULL && stack_pile->page_cell != NULL;) {
		stack_pile = ptgui_page_return_pile(stack_pile, control);
	}

	return stack_pile;
}

static	ptgui_page_transfer_mode_t	const transfer_process[] =
{
	{	ptgui_page_change_pile,		PTGUI_PAGE_LEVEL_KEEP	},
	{	ptgui_page_ride_pile,		PTGUI_PAGE_LEVEL_UP		},
	{	ptgui_page_return_pile,		PTGUI_PAGE_LEVEL_DOWN	},
	{	ptgui_page_rewind_pile,		PTGUI_PAGE_LEVEL_REWIND	},
};

static	ptgui_page_stack_t * ptgui_page_delete_useless_pile(ptgui_page_stack_t *Stack, const ptgui_page_cell_t *Current)
{
	ptgui_page_stack_t *ppPile;
	ptgui_page_stack_t *Pile;
	ptgui_page_stack_t *PileBack;

	rt_uint8_t i;
	ptgui_page_control_t Bucket;		/*	 Transfer control  Bucket 	*/

	ptgui_memcpy(&Bucket, &lastTransferCtrlBucket, sizeof(Bucket));

	ppPile = pile_stack_array + piple_stack_count - 1; 
	PileBack = Stack;

	for (i = 0; i < piple_stack_count ; i++) {
		Pile = ppPile - i;
		if (Pile == Stack) {
			break;
		}
		else {
			ptgui_page_make_transfer_control_bucket(PAGE_RETURN, Current, PTGUI_PAGE_LAYER_MAKE_NORMAL(0));
			PileBack = ptgui_page_return_pile(Pile, &lastTransferCtrlBucket);
		}
	}
	ptgui_memcpy(&lastTransferCtrlBucket, &Bucket, sizeof(lastTransferCtrlBucket));
	return PileBack;
}

ptgui_status_t ptgui_page_do_transfer_process(ptgui_page_control_t control)
{
	const	ptgui_page_transfer_mode_t *Process;
	ptgui_page_stack_t *Layer;

	ptgui_page_stack_t *ppPile;


	if (!control) {
		return PTGUI_STATUS_FAILED;
	}

	/*	transfer requese stack_pile Upper Layer   stack_pile  Delete 	*/
	if (0 >= piple_stack_count) {
		return PTGUI_STATUS_FAILED;
	}

	Layer = lastRecentPile;
	ppPile = pile_stack_array + piple_stack_count - 1; 
	if (lastRecentPile != ppPile) {
		if (!(control->transfer_status & INHERIT_ON)) {
			//Layer = ptgui_page_delete_useless_pile(Layer, piple_stack_count);
		}
	}
	else {
		Layer = ppPile;
	}

	/*	 Transfer Process  DO	*/
	for (Process = transfer_process; Process->transfer_switch; Process++) {
		if ((control->transfer_status) & (Process->transfer_switch)) {
			(*(Process->transfer_function))(Layer, control);
			break;
		}
	}

	return PTGUI_STATUS_SUCCESS;
}

static	ptgui_page_control_t ptgui_page_do_func_process(ptgui_page_event_handler_t  event_handler, ptgui_event_t *event,
											 ptgui_page_stack_t *stack_pile)
{
	ptgui_page_control_t control;

	lastRecentPile = stack_pile;
	control = (*event_handler)(event);

	if (control && control != (ptgui_page_control_t)ptgui_page_transfer_break) {
		ptgui_page_do_transfer_process(control);
	}

	return control;
}

#define	isAvailEventAccept(event)	((event)&&((event)->event_id)&&((event)->event_handler))
static ptgui_page_event_handler_t ptgui_page_search_event_accept_table(ptgui_event_t *event, const ptgui_page_cell_t *Page)
{
	ptgui_page_event_accept_t *event_accept;

	for (event_accept = (ptgui_page_event_accept_t *)(Page->event_accept); isAvailEventAccept(event_accept);
		 event_accept++) {
		if (event_accept->event_id == event->id) {
			return event_accept->event_handler;
		}
	}

	return NULL;
}

static	void ptgui_page_do_key_trigger(void)
{
	if(NULL != lastSwitchView) {
		if (lastSwitchView->event_handler) {
			ptgui_page_do_func_process(lastSwitchView->event_handler,
				&lastKeyEvent,lastProcessPile);
		}
	}
}

static ptgui_page_control_t ptgui_page_do_event_process(ptgui_event_t *event)
{
	ptgui_page_stack_t *stack_pile;			
	ptgui_page_control_t control;
	ptgui_page_event_handler_t event_handler;

	control = NULL;
	if (0 == piple_stack_count) {
		return control;
	}

	stack_pile = pile_stack_upper_top; 	
	while(stack_pile >= pile_stack_array) {
		key_event_break_flag = RT_FALSE;
		if ((!stack_pile) || (!stack_pile->page_cell)) {
			stack_pile--;
			continue;
		}

		event_handler = ptgui_page_search_event_accept_table(event, stack_pile->page_cell);
		if (event_handler != NULL) {
			control = ptgui_page_do_func_process(event_handler, event, stack_pile);			
			if (key_event_break_flag) {
				control = PTGUI_PAGE_TRAN_BREAK_FUNC;
			}

			if (control == PTGUI_PAGE_TRAN_BREAK_FUNC) {
				return control;
			}
		}

		stack_pile--;
	}

	return control;
}

static ptgui_page_control_t ptgui_page_do_event_process_r(ptgui_event_t *event)
{
	ptgui_page_stack_t *stack_pile;			
	ptgui_page_control_t control;
	ptgui_page_event_handler_t event_handler;

	control = NULL;
	if (0 == piple_stack_count) {
		return control;
	}

	stack_pile = pile_stack_lower_base; 	
	while(stack_pile <= pile_stack_upper_top) {
		key_event_break_flag = RT_FALSE;
		if ((!stack_pile) || (!stack_pile->page_cell)) {
			stack_pile++;
			continue;
		}

		event_handler = ptgui_page_search_event_accept_table(event, stack_pile->page_cell);
		if (event_handler != NULL) {
			control = ptgui_page_do_func_process(event_handler, event, stack_pile);			
			if (key_event_break_flag) {
				control = PTGUI_PAGE_TRAN_BREAK_FUNC;
			}
			if (control == PTGUI_PAGE_TRAN_BREAK_FUNC) {
				return control;
			}
		}

		stack_pile++;
	}

	return control;
}

static	void ptgui_page_set_boot_page(void)
{
	pile_stack_lower_base[0].page_cell = PTGUI_PAGE_REF_PAGECELL(FP_PAGE_BOOT);

	ptgui_page_make_transfer_control_bucket(PAGE_CHANGE, PTGUI_PAGE_REF_PAGECELL(FP_PAGE_BOOT),
											PTGUI_PAGE_LAYER_MAKE_LOWER(0));
	ptgui_page_stack_register(pile_stack_lower_base, &lastTransferCtrlBucket);
	ptgui_page_pile_transform(pile_stack_lower_base, PTGUI_PAGE_PREPARE_FST, 0);	
	ptgui_page_pile_transform(pile_stack_lower_base, PTGUI_PAGE_PREPARE_ALL, 0);	

	pile_stack_lower_top++;
	piple_stack_count = 1;
}

void ptgui_page_system_init(void)
{
	lastRecentPile = NULL;
	key_event_break_flag = RT_FALSE;

	ptgui_memset(&lastTransferCtrlBucket, 0, sizeof(lastTransferCtrlBucket));

	ptgui_memset(&current_cursor_info, 0, sizeof(current_cursor_info));
	ptgui_memset(&moved_cursor_info, 0, sizeof(moved_cursor_info));

	piple_stack_count = 0;
	ptgui_memset(pile_stack_array, 0, sizeof(pile_stack_array));
	pile_stack_lower_base = pile_stack_array;
	pile_stack_normal_base = pile_stack_lower_base + PTGUI_PAGE_LAYER_LOWER_MAX;
	pile_stack_upper_base = pile_stack_normal_base + PTGUI_PAGE_NORMAL_STACK_MAX;

	pile_stack_lower_top = pile_stack_lower_base;
	pile_stack_normal_top = pile_stack_normal_base;
	pile_stack_upper_top = pile_stack_upper_base;

	ptgui_page_set_boot_page();
}

void ptgui_page_controller_do_mouse(void)
{
	struct ptgui_event_mouse event;

	PTGUI_EVENT_MOUSE_BUTTON_INIT(&event);

	ptgui_page_do_event_process(&event.parent);
}

void ptgui_page_controller_do_frame(rt_uint32_t delta)
{
	struct ptgui_event_frame event;

	PTGUI_EVENT_FRAME_INIT(&event);
	event.delta = delta;

	ptgui_page_do_event_process_r(&event.parent);
}

void ptgui_page_controller_do_render(void)
{
	struct ptgui_event_paint event;

	PTGUI_EVENT_PAINT_INIT(&event);

	ptgui_page_do_event_process_r(&event.parent);	
}